using System;
using System.Collections.Generic;
using System.Text.RegularExpressions;

namespace DynamicExpresso;

/// <summary>
/// Interpreter扩展类
/// </summary>
public static class EvalHelper
{
	/// <summary>
	/// 包含英文的正则表达式
	/// </summary>
	public const string RegexChar = "[A-Za-z_]+";

	/// <summary>
	/// 包含中文、英文的正则表达式
	/// </summary>
	public const string RegexCharZH = "[\u4E00-\u9FA5A-Za-z_]+";

	/// <summary>
	/// 包含中文的正则表达式
	/// </summary>
	public const string RegexZH = "[\u4E00-\u9FA5_]+";

	/// <summary>
	/// 比较操作符
	/// </summary>
	public static readonly List<string> CampareOperators = [
			"<>", "!=",">=", ">","<=", "<","="];

	/// <summary>
	/// 表达式支持的操作符  character
	/// </summary>
	public static readonly List<string> ExpressionOperators = ["==", "!=", ">", ">=", "<", "<=",
	"&&", "||", "+", "-", "*", "/", "%", "^", "!", "(", ")", ":", "?"];

	/// <summary>
	/// 特殊字符。部分字符可能被解析为操作符，需要排除
	/// </summary>
	public static readonly List<string> SpecialChars = ["+", "-", "*", "/", "%"];

	/// <summary>
	/// 判断表达式是否为布尔值
	/// </summary>
	/// <param name="interpreter"></param>
	/// <param name="expressionText"></param>
	/// <returns></returns>
	public static bool EvalBool(this Interpreter interpreter, string expressionText)
	{
		if (expressionText.Contains("<>"))
		{
			expressionText = expressionText.Replace("<>", "!=");
		}
		if (expressionText.Contains(">=") || expressionText.Contains(">") ||
			expressionText.Contains("<=") || expressionText.Contains("<") ||
			expressionText.Contains("==") || expressionText.Contains("!="))
		{
			try
			{
				return interpreter.Eval<bool>(expressionText);
			}
			catch
			{
				//表达式错误，使用自定义计算方式
			}
		}
		return CompareString(expressionText);
	}

	/// <summary>
	/// 计算表达式，并返回字符串值
	/// </summary>
	/// <param name="interpreter"></param>
	/// <param name="expressionText"></param>
	/// <returns></returns>
	public static string EvalString(this Interpreter interpreter, string expressionText)
	{
		if (string.IsNullOrEmpty(expressionText)) return expressionText;
		//表达式最少为2个字符
		if (expressionText.Length < 2) return expressionText;
		//排除百分比 0.1%
		if (expressionText.Trim().EndsWith("%")) return expressionText;
		//四则运算后面为00，不是有效的四则运算
		if (expressionText.Contains("-00") || expressionText.Contains("+00")
			|| expressionText.Contains("*00"))
			return expressionText;
		if (expressionText.Contains("??"))
		{
			var vs = expressionText.Split(["??"], StringSplitOptions.None);
			return string.IsNullOrWhiteSpace(vs[0]) ? vs[1] : vs[0];
		}
		if (expressionText.Contains("null"))
		{
			return GetNullValue(expressionText);
		}
		if (expressionText.Contains("?") && expressionText.Contains(":"))
		{
			var strs = expressionText.Split(["?", ":"], StringSplitOptions.None);
			return interpreter.EvalBool(strs[0]) ? strs[1] : strs[2];
		}
		if ((expressionText.Contains("?") || expressionText.Contains("<")
			|| expressionText.Contains(">")) && expressionText.Contains("#"))
		{
			return GetMultiValue(expressionText);
		}
		if (IsMatchDateTime(expressionText)) return expressionText;
		if (ExpressionOperators.Exists(expressionText.Contains))
		{
			//包含中文、英文字符直接返回
			if (IsMatch(expressionText, RegexCharZH))
				return expressionText;
			//连加、连减、连乘、连除、连取模的情况暂不考虑
			//包含多个减号，且不包含括号，直接返回，如330000-20241015-4-0000
			if (IsMultiChar(expressionText, "-") && !expressionText.Contains("("))
				return expressionText;
			//包含多个加号，且不包含括号，直接返回，如330000-20241015-4-0000
			if (IsMultiChar(expressionText, "+") && !expressionText.Contains("("))
				return expressionText;
			//if (SpecialChars.Exists(expressionText.Contains))
			//{
			//}
			var value = interpreter.Eval<string>(expressionText);
			//表达式解析后不为null，为null说明解析错误了
			return value is null ? expressionText : value;
		}
		return expressionText;
	}

	/// <summary>
	/// 是否匹配
	/// </summary>
	/// <param name="value"></param>
	/// <param name="regex"></param>
	/// <returns></returns>
	public static bool IsMatch(string value, string regex)
	{
		if (string.IsNullOrWhiteSpace(value)) return false;
		Regex r = new(regex);
		return r.IsMatch(value);
	}

	/// <summary>
	/// 是否为有效的日期、时间格式
	/// </summary>
	/// <param name="date"></param>
	/// <returns></returns>
	public static bool IsMatchDateTime(string date)
	{
		if (string.IsNullOrWhiteSpace(date)) return false;
		if (date.Contains("-"))
		{
			return date.Contains(":")
				? Regex.IsMatch(date, @"^\d{4}-\d{2}-\d{2} ([01]?[0-9]|2[0-3]):[0-5][0-9]:[0-5][0-9]$")
				: Regex.IsMatch(date, @"^\d{4}-\d{2}-\d{2}$");
		}
		else if (date.Contains("/"))
		{
			return date.Contains(":")
				? Regex.IsMatch(date, @"^\d{4}/\d{2}/\d{2} ([01]?[0-9]|2[0-3]):[0-5][0-9]:[0-5][0-9]$")
				: Regex.IsMatch(date, @"^\d{4}/\d{2}/\d{2}$");
		}
		else if (date.Contains("年") && date.Contains("月") && date.Contains("日"))
		{
			return date.Contains(":")
				? Regex.IsMatch(date, @"^\d{4}年\d{2}月\d{2}日 ([01]?[0-9]|2[0-3]):[0-5][0-9]:[0-5][0-9]$")
				: Regex.IsMatch(date, @"^\d{4}年\d{2}月\d{2}日$");
		}
		else if (date.Contains(":"))
		{
			return Regex.IsMatch(date, @"^([01]?[0-9]|2[0-3]):[0-5][0-9]:[0-5][0-9]$");
		}

		return false;
	}

	/// <summary>
	/// 判断指定的字符是否存在多个
	/// </summary>
	/// <param name="value">被检查的字符串</param>
	/// <param name="charValue">存在多个的字符</param>
	/// <returns></returns>
	public static bool IsMultiChar(string value, string charValue)
	{
		if (!value.Contains(charValue)) return false;
		var sIdx = value.IndexOf(charValue);
		var eIdx = value.LastIndexOf(charValue);
		return eIdx > sIdx;
	}

	/// <summary>
	/// 比较字符串
	/// </summary>
	/// <param name="s1"></param>
	/// <param name="s2"></param>
	/// <param name="op"></param>
	/// <returns></returns>
	private static bool CompareString(string s1, string s2, string op)
	{
		if (double.TryParse(s1, out var d1) && double.TryParse(s2, out var d2))
		{
			return op switch
			{
				"==" or "=" => d1 == d2,
				"<>" or "!=" => d1 != d2,
				">=" => d1 >= d2,
				"<=" => d1 <= d2,
				">" => d1 > d2,
				"<" => d1 < d2,
				_ => false,
			};
		}
		var cp = s1.CompareTo(s2);
		return op switch
		{
			"==" or "=" => s1.Equals(s2, StringComparison.CurrentCultureIgnoreCase),
			"<>" or "!=" => !s1.Equals(s2, StringComparison.CurrentCultureIgnoreCase),
			">=" or ">" => cp > 0,
			"<=" or "<" => cp < 0,
			_ => false,
		};
	}

	/// <summary>
	/// 比较字符串
	/// </summary>
	/// <param name="text"></param>
	/// <returns></returns>
	private static bool CompareString(string text)
	{
		foreach (var s in CampareOperators)
		{
			if (!text.Contains(s)) continue;
			var strs = text.Split([s], StringSplitOptions.None);
			return CompareString(strs[0].Trim(), strs[1].Trim(), s);
		}
		return false;
	}

	/// <summary>
	/// 获取多值判断条件的值
	/// </summary>
	/// <param name="text"></param>
	/// <returns></returns>
	private static string GetMultiValue(string text)
	{
		var strs = text.Replace("?", "<").Split(["#"], StringSplitOptions.None);
		var len = strs.Length;
		(var s, var op, var e) = SplitValue(strs[0]);
		for (var i = 1; i < len; i++)
		{
			(var si, var opi, var ei) = SplitValue(strs[i]);
			if (string.IsNullOrWhiteSpace(op)) return si;
			var isTrue = CompareString(s, e, op);
			if (isTrue) return si;
			op = opi;
			e = ei;
		}
		return text;
	}

	/// <summary>
	/// 获取null值
	/// </summary>
	/// <param name="text"></param>
	/// <returns></returns>
	private static string GetNullValue(string text)
	{
		var noEqual = text.Contains("!=") || text.Contains("<>");
		string[] sp = noEqual switch
		{
			true => ["!=", "<>", "?", ":"],
			_ => ["=", "?", ":"]
		};
		var strs = text.Split(sp, StringSplitOptions.None);
		var isNull = "null" == strs[1].Trim();
		var len = strs.Length;
		if (len == 2)//判断是否成立
		{
			if (isNull)
			{
				if (noEqual) return string.IsNullOrWhiteSpace(strs[0]) ? "false" : "true";
				return string.IsNullOrWhiteSpace(strs[0]) ? "true" : "false";
			}
			else
			{
				if (noEqual) return string.IsNullOrWhiteSpace(strs[0]) ? "true" : "false";
				return string.IsNullOrWhiteSpace(strs[0]) ? "false" : "true";
			}
		}
		if (string.IsNullOrWhiteSpace(strs[0]))
		{
			if (isNull)
				return noEqual ? (len > 3 ? strs[3] : strs[0]) : strs[2];
			else
				return noEqual ? strs[2] : (len > 3 ? strs[3] : strs[0]);
		}
		else
		{
			if (isNull)
				return noEqual ? strs[2] : (len > 3 ? strs[3] : strs[0]);
			else
				return noEqual ? (len > 3 ? strs[3] : strs[0]) : strs[2];
		}
	}

	/// <summary>
	///
	/// </summary>
	/// <param name="text"></param>
	/// <returns></returns>
	private static (string s, string op, string e) SplitValue(string text)
	{
		if (text.Contains("<=")) return SplitValue(text, "<=");
		if (text.Contains("<")) return SplitValue(text, "<");
		if (text.Contains(">=")) return SplitValue(text, ">=");
		if (text.Contains(">")) return SplitValue(text, ">");
		if (text.Contains("==")) return SplitValue(text, "==");
		if (text.Contains("!=")) return SplitValue(text, "!=");
		if (text.Contains("=")) return SplitValue(text, "=");
		return (text, "", "");
	}

	/// <summary>
	/// 获取分割的值
	/// </summary>
	/// <param name="text"></param>
	/// <param name="splitChar"></param>
	/// <returns></returns>
	private static (string s, string op, string e) SplitValue(string text, string splitChar)
	{
		var strs = text.Split([splitChar], StringSplitOptions.None);
		return (strs[0].Trim(), splitChar, strs[1].Trim());
	}
}
